//使用参见《NC Cloud最终用户许可协议》，协议内容详见安装目录
package nc.impl.hrpbm.budgetadjust.budgetadjust;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import nc.bs.logging.Logger;
import nc.itf.pmpub.prv.IProjectQuery;
import nc.vo.hrpbm.budgetadjust.*;
import nc.vo.hrpbm.budgetmake.*;
import nc.vo.pmpub.project.ProjectHeadVO;
import nc.vo.pub.ISuperVO;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

import nc.bs.dao.BaseDAO;
import nc.bs.framework.common.InvocationInfoProxy;
import nc.bs.framework.common.NCLocator;
import nc.bs.hrpbm.budgetmake.util.CheckAboutHrppl;
import nc.hrpbctp.control.pub.BctpControlAmountCheckException;
import nc.hrpbm.impl.control.service.BmBudgetControlServiceImpl;
import nc.impl.hrpbm.budgetmake.budgetmake.BudgetMakeVOServiceImpl;
import nc.impl.pubapp.pattern.data.vo.VOQuery;
import nc.impl.pubapp.pattern.data.vo.VOUpdate;
import nc.itf.hrpbm.budgetadjust.budgetadjust.IBudgetAdjustVOService;
import nc.itf.hrpbm.budgetmake.budgetmake.IBudgetMakeVOService;
import nc.jdbc.framework.processor.ColumnListProcessor;
import nc.pub.billcode.vo.BillCodeContext;
import nc.vo.hrpbm.hrpbmpubenum.TaskStageEnum;
import nc.vo.hrpbm.hrpbmpubenum.TaskStateEnum;
import nc.vo.ml.NCLangRes4VoTransl;
import nc.vo.pub.AggregatedValueObject;
import nc.vo.pub.BusinessException;
import nc.vo.pub.CircularlyAccessibleValueObject;
import nc.vo.pub.SuperVO;
import nc.vo.pub.VOStatus;
import nc.vo.pub.lang.UFBoolean;
import nc.vo.pub.lang.UFDateTime;
import nc.vo.pub.lang.UFDouble;
import nc.vo.pub.pf.BillStatusEnum;
import nccloud.hrpbm.budget.util.GenerateBudgetNo;
import nccloud.hrpbm.budget.util.GetIdCode;
import nccloud.hrpbm.budget.util.SetChildColumnValue;
import nccloud.hrpbm.budget.util.ValidateAssetAllocation;
import nccloud.hrpbm.budget.util.ValidateBudgetDetail;
import nccloud.hrpbm.budget.util.ValidateChildLength;
import nccloud.hrpbm.budget.util.ValidateOtherTwoChildLength;
import nccloud.impl.hrpbm.pub.common.HrpbmServiceSupport;
import nccloud.pubitf.riart.pflow.CloudPFlowContext;

public class BudgetAdjustVOServiceImpl extends HrpbmServiceSupport implements IBudgetAdjustVOService {
    private BaseDAO daoSql = new BaseDAO();

    @Override
    public AggBudgetAdjustVO[] listAggBudgetAdjustVOByPk(String... pks) throws BusinessException {
        return listAggBudgetAdjustVOByPk(false, pks);
    }

    @Override
    public AggBudgetAdjustVO[] listAggBudgetAdjustVOByPk(boolean blazyLoad, String... pks) throws BusinessException {
        return dao.listByPksWithOrder(AggBudgetAdjustVO.class, pks, blazyLoad);
    }

    @Override
    public AggBudgetAdjustVO findAggBudgetAdjustVOByPk(String pk) throws BusinessException {
        return dao.findByPk(AggBudgetAdjustVO.class, pk, false);
    }

    @Override
    public AggBudgetAdjustVO[] listAggBudgetAdjustVOByCondition(String condition) throws BusinessException {
        return listAggBudgetAdjustVOByCondition(condition, new String[]{"pk_budgetadjust"});
    }

    @Override
    public AggBudgetAdjustVO[] listAggBudgetAdjustVOByCondition(String condition, String[] orderPath)
            throws BusinessException {
        return dao.listByCondition(AggBudgetAdjustVO.class, condition, false, false, orderPath);
    }

    @Override
    public BudgetAdjustVO[] listBudgetAdjustVOByPk(String... pks) throws BusinessException {
        return dao.listByPk(BudgetAdjustVO.class, pks, true);
    }

    @Override
    public BudgetAdjustVO findBudgetAdjustVOByPk(String pk) throws BusinessException {
        return dao.findByPk(BudgetAdjustVO.class, pk, true);
    }

    @Override
    public BudgetAdjustVO[] listBudgetAdjustVOByCondition(String condition) throws BusinessException {
        return listBudgetAdjustVOByCondition(condition, new String[]{"pk_budgetadjust"});
    }

    @Override
    public BudgetAdjustVO[] listBudgetAdjustVOByCondition(String condition, String[] orderPath)
            throws BusinessException {
        return dao.listByCondition(BudgetAdjustVO.class, condition, false, false, orderPath);
    }

    @Override
    public String[] listBudgetAdjustVOPkByCond(String condition) throws BusinessException {
        return listBudgetAdjustVOPkByCond(condition, new String[]{"pk_budgetadjust"});
    }

    @Override
    public String[] listBudgetAdjustVOPkByCond(String condition, String[] orderPath) throws BusinessException {
        if (StringUtils.isEmpty(condition)) {
            condition = " 1 = 1 ";
        }
        BudgetAdjustVO[] vos = dao.listByCondition(BudgetAdjustVO.class, condition, false, false, orderPath);
        if (ArrayUtils.isEmpty(vos)) {
            return null;
        }
        return Arrays.stream(vos).map(vo -> vo.getPrimaryKey()).toArray(String[]::new);
    }

    @Override
    public void initDefaultData(BudgetAdjustVO vo) {
        if (vo.getAttributeValue("pk_group") == null) {
            vo.setAttributeValue("pk_group", InvocationInfoProxy.getInstance().getGroupId());
        }
        if (vo.getAttributeValue("billmaker") == null) {
            vo.setAttributeValue("billmaker", InvocationInfoProxy.getInstance().getUserId());
        }
        if (vo.getAttributeValue("maketime") == null) {
            vo.setAttributeValue("maketime", new UFDateTime(InvocationInfoProxy.getInstance().getBizDateTime()));
        }
        if (vo.getAttributeValue("billtype") == null) {
            vo.setAttributeValue("billtype", "BM30");
        }
        if (vo.getAttributeValue("approvestatus") == null) {
            vo.setAttributeValue("approvestatus", BillStatusEnum.FREE.toIntValue());
        }
    }

    @Override
    public AggBudgetAdjustVO preAddAggBudgetAdjustVO(AggBudgetAdjustVO vo, Map<String, Object> userJson)
            throws BusinessException {

        getMainVO(vo).setStatus(VOStatus.NEW);
        initDefaultData((BudgetAdjustVO) getMainVO(vo));

        // 下面这段要判断是否是树表界面插件
        Map<String, String> data = userJson != null && userJson.get("data") != null
                ? (Map<String, String>) userJson.get("data")
                : null;
        if (data != null && data.size() > 0) {
            String parentKey = data.get("parentKey");
            String parentPk = data.get("parentPk");
            getMainVO(vo).setAttributeValue(parentKey, parentPk);
        }

        return vo;
    }

    @Override
    public AggBudgetAdjustVO preAddAggBudgetAdjustVO(Map<String, Object> userJson) throws BusinessException {
        AggBudgetAdjustVO result = null;

        BudgetAdjustVO mainvo = new BudgetAdjustVO();
        // 设置默认值
        initDefaultData(mainvo);
        AggBudgetAdjustVO aggvo = new AggBudgetAdjustVO();
        aggvo.setParent(mainvo);
        result = aggvo;
        return preAddAggBudgetAdjustVO(result, userJson);
    }

    @Override
    public AggBudgetAdjustVO preEditAggBudgetAdjustVO(String pk) throws BusinessException {
        return dao.findByPk(AggBudgetAdjustVO.class, pk, false);
    }

    @Override
    public AggBudgetAdjustVO[] saveAggBudgetAdjustVO(AggBudgetAdjustVO vo) throws BusinessException {
        String pk = getVOPrimaryKey(vo);
        setDefaultVal(vo);
        writeMakeBillAdjust(vo, "save");

        AggBudgetAdjustVO[] results = null;

        AggBudgetAdjustVO oriAdjustVo = null;//ADD BY WW 2024-04-07 调减预算支持冻结：保存时增加冻结金额

        // 表体引用了项目库项目并开启相关参数则进行校验
        CheckAboutHrppl.check_budgetAdjust(vo);

        if (StringUtils.isEmpty(pk)) {
            results = dao.insert(vo); // 插入
        } else {
            oriAdjustVo = this.findAggBudgetAdjustVOByPk(vo.getPrimaryKey());//ADD BY WW 2024-04-07 调减预算支持冻结：保存时增加冻结金额
            results = dao.update(vo); // 更新
        }

        // 保存时 推送预算（校验余额、冻结）
        pushBudgetForSave(results[0], oriAdjustVo, true);

        return results;

    }


    @Override
    public AggBudgetAdjustVO[] saveAggBudgetAdjustVO(AggBudgetAdjustVO vo, boolean isAgain) throws BusinessException {
        String pk = getVOPrimaryKey(vo);
        setDefaultVal(vo);
        writeMakeBillAdjust(vo, "save");

        AggBudgetAdjustVO[] results = null;

        AggBudgetAdjustVO oriAdjustVo = null;//ADD BY WW 2024-04-07 调减预算支持冻结：保存时增加冻结金额

        // 表体引用了项目库项目并开启相关参数则进行校验
        CheckAboutHrppl.check_budgetAdjust(vo);
        checkDataComplete(vo);
        checkDataAdjustType(vo);
        //新增资产中项目合计“金额”要小于等于政采中对应项目的合计“金额”。否则给出提示：**项目，新增资产预算不能大于政府采购预算，请修改，不允许保存
        checkGovAndAssetMoney(vo);

        if (!isAgain) {
            //如果被调整金额的表体行项目包含绩效目标，保存则给出提示：被调整金额的项目包含绩效目标信息，是否要进行调整？点“确定”，不保存。点“取消”，保存。
            if (checkPerformanceProjects(vo)) {
                return new AggBudgetAdjustVO[]{vo};
            }
        }

        if (StringUtils.isEmpty(pk)) {
            results = dao.insert(vo); // 插入
        } else {
            oriAdjustVo = this.findAggBudgetAdjustVOByPk(vo.getPrimaryKey());//ADD BY WW 2024-04-07 调减预算支持冻结：保存时增加冻结金额
            results = dao.update(vo); // 更新
        }


        try {

            //重复保存时不进行余额校验
            boolean isNeedCheck = !isAgain;

            // 保存时 推送预算（校验余额、冻结）
            pushBudgetForSave(results[0], oriAdjustVo, isNeedCheck);

        } catch (BctpControlAmountCheckException e) {
//            Budgettype budgettypevo = NCLocator.getInstance().lookup(IBudgettypeService.class).findBudgettypeByPk
//            (vo.getParentVO().getPk_budgettype(), true);
//            if (budgettypevo.getInnercode().startsWith("YS05")) {
            results[0].getParentVO().setShowModal(true);
            results[0].getParentVO().setModalMessage(e.getMessage() + "是否继续？");
//            } else {
//                throw e;
//            }
        }

        return results;

    }


    /**
     * 如果被调整金额的表体行项目包含绩效目标，
     * 保存则给出提示：被调整金额的项目包含绩效目标信息，是否要进行调整？
     * 点“确定”，不保存。点“取消”，保存。
     *
     * @param vo
     * @return
     * @throws BusinessException
     */
    private boolean checkPerformanceProjects(AggBudgetAdjustVO vo) throws BusinessException {
        BudgetAdjustDetailVO[] detailVOS = (BudgetAdjustDetailVO[]) vo.getChildren(BudgetAdjustDetailVO.class);
        List<String> projectPks = Arrays.stream(detailVOS)
                .map(BudgetAdjustDetailVO::getPk_project)
                .filter(StringUtils::isNotEmpty)
                .distinct().toList();
        if (projectPks.isEmpty()) {
            return false;
        }

        String condition = projectPks.stream()
                .map(pk -> "'" + pk + "'")
                .collect(Collectors.joining(",", "pk_project in (", ")"));
        ProjectHeadVO[] projectHeadVO = dao.listByCondition(ProjectHeadVO.class, condition);
        if (projectHeadVO != null && projectHeadVO.length > 0) {
            for (ProjectHeadVO project : projectHeadVO) {
                UFBoolean bperformance = Optional.ofNullable(project.getAttributeValue("bperformance"))
                        .map(Object::toString)
                        .map(UFBoolean::new)
                        .orElse(UFBoolean.FALSE);
                if (bperformance.booleanValue()) {
                    vo.getParentVO().setShowModal(true);
                    vo.getParentVO().setModalMessage("项目包含绩效目标信息，是否跳过不做绩效目标调整?");
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 新增资产中项目合计“金额”要小于等于政采中对应项目的合计“金额”。
     * 否则给出提示：**项目，新增资产预算不能大于政府采购预算，请修改，不允许保存
     *
     * @param vo
     * @throws BusinessException
     */
    private void checkGovAndAssetMoney(AggBudgetAdjustVO vo) throws BusinessException {


        // 获取子表数据
        AdjustGovPurchVO[] govpurvos = (AdjustGovPurchVO[]) vo.getChildren(AdjustGovPurchVO.class);
        AdjustAssetAllocationVO[] assetvos = (AdjustAssetAllocationVO[]) vo.getChildren(AdjustAssetAllocationVO.class);

        // 将子表数据转换为Map
        Map<String, UFDouble> govMoneyMap = getMoneyMap(govpurvos, AdjustGovPurchVO::getPk_project,
                AdjustGovPurchVO::getMoney);
        Map<String, UFDouble> assetMoneyMap = getMoneyMap(assetvos, AdjustAssetAllocationVO::getPk_project,
                AdjustAssetAllocationVO::getMoney);

        // 获取所有项目PK并查询项目名称
        List<String> projectPks = new ArrayList<>();
        projectPks.addAll(govMoneyMap.keySet());
        projectPks.addAll(assetMoneyMap.keySet());
        Map<String, String> projectPkAndName = getProjectNames(projectPks);

        // 验证资产金额与政府采购金额
        validateAssetMoney(assetMoneyMap, govMoneyMap, projectPkAndName);


    }

    // 将子表数据转换为Map
    private <T> Map<String, UFDouble> getMoneyMap(T[] vos, Function<T, String> keyMapper,
                                                  Function<T, UFDouble> valueMapper) {
        if (vos == null) {
            return new HashMap<>();
        }
        return Arrays.stream(vos)
                .collect(Collectors.toMap(
                        keyMapper,
                        valueMapper,
                        UFDouble::add
                ));
    }

    // 查询项目名称
    private Map<String, String> getProjectNames(List<String> projectPks) throws BusinessException {
        IProjectQuery projectQuery = NCLocator.getInstance().lookup(IProjectQuery.class);
        ProjectHeadVO[] headVOS = projectQuery.queryProjectHeadVOsBypks(projectPks.toArray(new String[0]));
        Map<String, String> projectPkAndName = new HashMap<>();
        if (headVOS != null) {
            for (ProjectHeadVO headvo : headVOS) {
                projectPkAndName.put(headvo.getPk_project(), headvo.getProject_name());
            }
        }
        return projectPkAndName;
    }

    // 验证资产金额与政府采购金额
    private void validateAssetMoney(Map<String, UFDouble> assetMoneyMap, Map<String, UFDouble> govMoneyMap,
                                    Map<String, String> projectPkAndName) throws BusinessException {
        StringBuffer error = new StringBuffer();
        if (!assetMoneyMap.isEmpty()) {
            for (Map.Entry<String, UFDouble> entry : assetMoneyMap.entrySet()) {
                String assetKey = entry.getKey();
                UFDouble assetMoney = entry.getValue();
                if (!govMoneyMap.containsKey(assetKey)) {
                    error.append("项目：").append(projectPkAndName.get(assetKey)).append("，在政府采购页签中没有，请检查！\n");
                } else {
                    UFDouble govMoney = govMoneyMap.get(assetKey);
                    if (assetMoney.compareTo(govMoney) > 0) {
                        error.append("项目：").append(projectPkAndName.get(assetKey))
                                .append("，新增资产中项目合计“金额”要小于等于政采中对应项目的合计“金额”。\n");
                    }
                }
            }
        }
        // 如果有错误信息则抛出异常
        if (error.length() > 0) {
            throw new BusinessException(error.toString());
        }
    }


    private void checkDataAdjustType(AggBudgetAdjustVO vo) {
        checkAdjustType(vo.getChildren(BudgetAdjustDetailVO.class));
        checkAdjustType(vo.getChildren(AdjustGovPurchVO.class));
        checkAdjustType(vo.getChildren(AdjustAssetAllocationVO.class));
    }

    private void checkAdjustType(ISuperVO[] vos) {
        if (ArrayUtils.isEmpty(vos)) {
            return;
        }
        Logger.error("enter function checkAdjustType ");
        for (ISuperVO vo : vos) {
            Logger.error(vo.getClass().getName() + " getAttributeValue(srcbillbid) is " + vo.getAttributeValue(
                    "srcbillbid"));
            if (null == vo.getAttributeValue("srcbillbid")) {
                vo.setAttributeValue("adjusttype", "1");
                continue;
            }
            if (!isAttributesEqual(vo, "amount_before_adjust", "amount_after_adjust")
                    || !isAttributesEqual(vo, "oldnum", "num")
                    || !isAttributesEqual(vo, "oldprice", "price")
                    || !isAttributesEqual(vo, "oldmoney", "money")
                    || !isAttributesEqual(vo, "oldassetnum", "assetnum")) { // 添加了对数量参数的检查
                vo.setAttributeValue("adjusttype", "2");
            } else {
                vo.setAttributeValue("adjusttype", null);
            }
        }
        Logger.error("leave function checkAdjustType ");
    }

    private boolean isAttributesEqual(ISuperVO vo, String attr1, String attr2) {
        Logger.error("enter function isAttributesEqual ");
        Logger.error("vo is " + vo.getClass().getName());
        Logger.error("attr1 is " + attr1);
        Logger.error("attr2 is " + attr2);
        Object value1 = vo.getAttributeValue(attr1);
        Object value2 = vo.getAttributeValue(attr2);
        Logger.error("leave function checkAdjustType ");
        return (value1 == null && value2 == null) || (value1 != null && value1.equals(value2));
    }


//    private void checkDataAdjustType(AggBudgetAdjustVO vo) {
//        ISuperVO[] detailVos = vo.getChildren(BudgetAdjustDetailVO.class);
//        ISuperVO[] govpurchVos = vo.getChildren(AdjustGovPurchVO.class);
//        ISuperVO[] assetVos = vo.getChildren(AdjustAssetAllocationVO.class);
//        for (ISuperVO detailVO : detailVos) {
//            if (null == detailVO.getAttributeValue("srcbillbid")) {
//                continue;
//            }
//            if (!detailVO.getAttributeValue("amount_before_adjust").equals(detailVO.getAttributeValue(
//                    "amount_after_adjust"))) {
//                detailVO.setAttributeValue("adjusttype", "2");
//            }else {
//                detailVO.setAttributeValue("adjusttype",null);
//            }
//        }
//
//        for (ISuperVO govpurchVO : govpurchVos) {
//            if (null == govpurchVO.getAttributeValue("srcbillbid")) {
//                continue;
//            }
//            if (!govpurchVO.getAttributeValue("oldnum").equals(govpurchVO.getAttributeValue("num"))
//                    || !govpurchVO.getAttributeValue("oldprice").equals(govpurchVO.getAttributeValue("price"))
//                    || !govpurchVO.getAttributeValue("oldmoney").equals(govpurchVO.getAttributeValue("money"))
//            ) {
//                govpurchVO.setAttributeValue("adjusttype", "2");
//            }else {
//                govpurchVO.setAttributeValue("adjusttype",null);
//            }
//
//        }
//
//        for (ISuperVO assetVO : assetVos) {
//            if (null == assetVO.getAttributeValue("srcbillbid")) {
//                continue;
//            }
//            if (!assetVO.getAttributeValue("oldassetnum").equals(assetVO.getAttributeValue("assetnum"))
//                    || !assetVO.getAttributeValue("oldprice").equals(assetVO.getAttributeValue("price"))
//                    || !assetVO.getAttributeValue("oldmoney").equals(assetVO.getAttributeValue("money"))
//            ) {
//                assetVO.setAttributeValue("adjusttype", "2");
//            }else {
//                assetVO.setAttributeValue("adjusttype",null);
//            }
//
//        }
//
//    }

    private void checkDataComplete(AggBudgetAdjustVO vo) throws BusinessException {
        if ((vo.getParentVO().getTranstype().contains("YS02") || vo.getParentVO().getTranstype().contains("YS04") ||
                vo.getParentVO().getTranstype().contains("YS03"))
                && (Objects.nonNull(vo.getChildren(AdjustGovPurchVO.class)) || Objects.nonNull(vo.getChildren(AdjustAssetAllocationVO.class)))) {
            StringBuffer errmsg = new StringBuffer();
            // 验证政府采购和资产分配页签是否必输
            ValidateOtherTwoChildLength.validateChildLength(vo, BudgetAdjustDetailVO.class, AdjustGovPurchVO.class,
                    AdjustAssetAllocationVO.class, errmsg);

            // 校验资产配置页签必输项
            ValidateAssetAllocation.check((SuperVO[]) vo.getChildren(AdjustAssetAllocationVO.class), errmsg);
            if (errmsg.length() > 0) {
                throw new BusinessException(errmsg.toString());
            }
        }


    }


    /**
     * 保存前设置审计信息
     *
     * @param vos
     */
    private void setAuditInfo(AggBudgetAdjustVO... vos) throws BusinessException {
        if (ArrayUtils.isNotEmpty(vos)) {
            UFDateTime now = new UFDateTime();
            for (AggBudgetAdjustVO vo : vos) {
                String pk = getVOPrimaryKey(vo);
                if (StringUtils.isEmpty(pk)) {
                    // 设置创建人创建时间
                    getMainVO(vo).setAttributeValue("creator", InvocationInfoProxy.getInstance().getUserId());
                    getMainVO(vo).setAttributeValue("creationtime", now);
                    getMainVO(vo).setAttributeValue("maketime", now);
                } else {
                    // 设置修改人修改时间
                    getMainVO(vo).setAttributeValue("modifier", InvocationInfoProxy.getInstance().getUserId());
                    getMainVO(vo).setAttributeValue("modifiedtime", now);
                    getMainVO(vo).setAttributeValue("lastmaketime", now);
                }
            }
        }
    }

    /**
     * 保存前处理一些默认值
     *
     * @param vos
     */
    private void setDefaultVal(AggBudgetAdjustVO... vos) throws BusinessException {
        setAuditInfo(vos);
        // 其他默认值处理
        // 生成预算号
        GenerateBudgetNo generateBudgetNo = new GenerateBudgetNo();
        generateBudgetNo.generateBudgetNo(vos);
    }

    // 给单表（行编辑表）单独适配
    @Override
    public AggBudgetAdjustVO[] saveAggBudgetAdjustVO(AggBudgetAdjustVO[] vos) throws BusinessException {
        setDefaultVal(vos);
        return dao.save(vos, true);
    }

    @Override
    public AggBudgetAdjustVO[] deleteAggBudgetAdjustVOs(Map<String, String> tsMap) throws BusinessException {
        AggBudgetAdjustVO[] vos = dao.listByPk(AggBudgetAdjustVO.class, tsMap.keySet().toArray(new String[0]));
        validate(vos, tsMap);
        dao.delete(vos, true);


        //ADD BY WW 2024-04-07 调减预算支持冻结：删除时减少冻结金额
        BmBudgetControlServiceImpl controlService = new BmBudgetControlServiceImpl();
        for (AggBudgetAdjustVO adjustVo : vos) {
            controlService.pushDataToControl(adjustVo.getParentVO().getPk_group(), adjustVo.getParentVO().getPk_org()
                    , "BM30", null, null, "DELETE", adjustVo, null, true);
        }


        return vos;
    }

    // 校验 包括ts校验
    private void validate(AggBudgetAdjustVO[] vos, Map<String, String> tsMap) throws BusinessException {

        Boolean isPass = true;
        if (ArrayUtils.isEmpty(vos)) {
            isPass = false;
        }
        for (AggBudgetAdjustVO vo : vos) {

            SuperVO mainvo = vo.getParentVO();
            UFDateTime ts = (UFDateTime) mainvo.getAttributeValue("ts");
            if (!StringUtils.equals(tsMap.get(mainvo.getPrimaryKey()), ts.toString())) {
                isPass = false;
                break;
            }
        }
        if (!isPass) {
            throw new BusinessException("您操作的数据已被他人修改或删除，请刷新后重试！");
        }
    }

    @Override
    public <T> T[] loadTreeData(Class<T> clazz, Map<String, Object> userJson) throws BusinessException {
        return dao.listByCondition(clazz, " dr = 0 ", false);
    }

    @Override
    public String[] queryChildPksByParentId(Class childClazz, String parentId) throws BusinessException {
        String cond = " pk_budgetadjust = '" + parentId + "' ";
        SuperVO[] vos = (SuperVO[]) dao.listByCondition(childClazz, cond, false);
        if (vos == null || vos.length == 0) {
            return new String[0];
        }
        return Stream.of(vos).map(vo -> vo.getPrimaryKey()).toArray(String[]::new);
    }

    public SuperVO[] queryChildVOByPks(Class childClazz, String[] pks) throws BusinessException {
        return (SuperVO[]) dao.listByPk(childClazz, pks, false);
    }

    /**
     * 提交前校验: 检查单据状态
     *
     * @throws BusinessException
     */
    private void validateCommitAggBudgetAdjustVO(AggBudgetAdjustVO... vos) throws BusinessException {
        if (ArrayUtils.isEmpty(vos)) {
            return;
        }
        List<AggBudgetAdjustVO> list = Arrays.stream(vos).filter(item -> item.getParentVO() != null).filter(item -> {
            Integer status = (Integer) item.getParentVO().getAttributeValue("approvestatus");
            return status == null
                    || status != BillStatusEnum.FREE.toIntValue() && status != BillStatusEnum.NOPASS.toIntValue();
        }).map(item -> item).collect(Collectors.toList());
        if (list == null || list.size() == 0) {
            return;
        }
        String errors = "";
        for (AggBudgetAdjustVO vo : list) {
            errors += "单据号：[" + vo.getParentVO().getAttributeValue("billno") + "]提交失败，失败原因：单据状态不正确，请检查。\n";
        }
        throw new BusinessException(errors);
    }

    /**
     * 收回前校验: 检查单据状态
     *
     * @throws BusinessException
     */
    private void validateUnCommitAggBudgetAdjustVO(AggBudgetAdjustVO... vos) throws BusinessException {
        if (ArrayUtils.isEmpty(vos)) {
            return;
        }
        List<AggBudgetAdjustVO> list = Arrays.stream(vos).filter(item -> item.getParentVO() != null).filter(item -> {
            Integer status = (Integer) item.getParentVO().getAttributeValue("approvestatus");
            return status == null || status == BillStatusEnum.FREE.toIntValue();
        }).map(item -> item).collect(Collectors.toList());
        if (list == null || list.size() == 0) {
            return;
        }
        String errors = "";
        for (AggBudgetAdjustVO vo : list) {
            errors += "单据号：[" + vo.getParentVO().getAttributeValue("billno") + "]提交失败，失败原因：单据状态不正确，请检查。\n";
        }
        throw new BusinessException(errors);
    }

    @Override
    public Map<String, Object> commitAggBudgetAdjustVO(String actionName, Map<String, String> tsMap, Object assign)
            throws BusinessException {
        AggBudgetAdjustVO[] vos = dao.listByPk(AggBudgetAdjustVO.class, getAllPks(tsMap), true);
        validateTs(tsMap, vos);
        // 提交前校验及业务逻辑
        validateCommitAggBudgetAdjustVO(vos);
        Map<String, Object> res = this.execFlows(actionName, "BM30", assign, vos);
        // 提交后业务逻辑
        // return vos[0];
        return res;
    }

    protected Map<String, Object> execFlows(String actionName, String pk_billtype, Object assign, Object... vos)
            throws BusinessException {
        if (StringUtils.isEmpty(pk_billtype)) {
            throw new BusinessException(NCLangRes4VoTransl.getNCLangRes().getStrByID("codebase", "0codebase0000"));
        }

        AggregatedValueObject[] aggvos = adpterVO2Agg(vos);
        CloudPFlowContext[] context = this.flowUtils.createContext(aggvos, actionName, pk_billtype);

        if (assign != null) {
            if (context != null && context.length == 1) {
                Map<Object, Object> param = context[0].geteParam() == null ? new HashMap<>() : context[0].geteParam();
                param.put("content", assign);
                context[0].seteParam(param);
            }
        }

        return this.flowUtils.execApplyFlow(context);
    }

    @Override
    public void batchCommitAggBudgetAdjustVO(String actionName, Map<String, String> tsMap) throws BusinessException {
        AggBudgetAdjustVO[] vos = dao.listByPk(AggBudgetAdjustVO.class, getAllPks(tsMap), true);
        validateTs(tsMap, vos);
        // 批量提交前校验及业务逻辑
        validateCommitAggBudgetAdjustVO(vos);
        Map<String, Object> res = this.execFlows(actionName, "BM30", vos);
        // 批量提交后业务逻辑
    }

    @Override
    public AggBudgetAdjustVO uncommitAggBudgetAdjustVO(String actionName, Map<String, String> tsMap)
            throws BusinessException {
        AggBudgetAdjustVO[] vos = dao.listByPk(AggBudgetAdjustVO.class, getAllPks(tsMap), true);

        //记录收回前的单据信息
        Map<String, Integer> beforeApproveStatusMap =
                Arrays.stream(vos).collect(Collectors.toMap(AggBudgetAdjustVO::getPrimaryKey,
                        vo -> vo.getParentVO().getApprovestatus()));

        validateTs(tsMap, vos);
        // 收回前校验及业务逻辑
        validateUnCommitAggBudgetAdjustVO(vos);
        if (checkUnapprovedByDimension(vos)) {
            throw new BusinessException("存在未审核完成单据，不允许取消审批/收回！");
        }
        if (checkApprovedByMakeBillNo(vos)) {
            throw new BusinessException("当前调整单还存在后续调整单，请按审核日期倒序依次进行取消审核！");
        }
        Map<String, Object> res = this.execFlows(actionName, "BM30", vos);

        Map<String, AggBudgetMakeVO> budgetMakeVoMap_beforeAdjust = new HashMap<String, AggBudgetMakeVO>();
        // 收回后业务逻辑
        for (AggBudgetAdjustVO aggBudgetAdjustVO : vos) {

            //只有从审批完成状态收回的时候才回写编制、推送预算
            int beforeApproveStatus = beforeApproveStatusMap.get(aggBudgetAdjustVO.getPrimaryKey());
            if (BillStatusEnum.APPROVED.toIntValue() != beforeApproveStatus)
                continue;

            String[] pk_budgetmakes = aggBudgetAdjustVO.getParentVO().getPk_budgetmake().split(",");

            AggBudgetMakeVO[] aggBudgetMakeVos = budgetMakeVoServiceImpl.listAggBudgetMakeVOByPk(pk_budgetmakes);

            for (AggBudgetMakeVO aggBudgetMakeVo : aggBudgetMakeVos) {
                budgetMakeVoMap_beforeAdjust.put(aggBudgetMakeVo.getPrimaryKey(), aggBudgetMakeVo);
            }

            // 将调整后的数据 同步到预算编制单中
            aggBudgetAdjustVO = writeMakeBillAdjust(aggBudgetAdjustVO, "unapprove");

            // 推送数据到预算执行监控
//            pushBudgetForApproveAndUnApprove(aggBudgetAdjustVO, budgetMakeVoMap_beforeAdjust, "UNADJUST");
            pushBudgetForApproveAndUnApprove(aggBudgetAdjustVO, "UNAPPROVE");

        }

        return vos[0];
    }

    @Override
    public void batchUncommitAggBudgetAdjustVO(String actionName, Map<String, String> tsMap) throws BusinessException {
        AggBudgetAdjustVO[] vos = dao.listByPk(AggBudgetAdjustVO.class, getAllPks(tsMap), true);
        validateTs(tsMap, vos);
        // 批量收回前校验及业务逻辑
        validateUnCommitAggBudgetAdjustVO(vos);
        Map<String, Object> res = this.execFlows(actionName, "BM30", vos);
        // 批量收回后业务逻辑
    }

    @Override
    public AggBudgetAdjustVO[] callbackSAVEBASE(AggBudgetAdjustVO... vos) throws BusinessException {
        if (ArrayUtils.isEmpty(vos)) {
            return null;
        }
        // 同步单据状态和审批状态(只有提交时候需要手动设置审批状态。其余审批完后审批状态都已更新)
        List<AggBudgetAdjustVO> update = new ArrayList<>(), insert = new ArrayList<>();
        Arrays.stream(vos).forEach(item -> {
            if (StringUtils.isEmpty(item.getPrimaryKey())) {
                insert.add(item);
            } else {
                update.add(item);
            }
        });
        List<AggBudgetAdjustVO> ret = new ArrayList<>();
        if (insert.size() > 0) {
            ret.addAll(Arrays.asList(dao.insert(insert.toArray(new AggBudgetAdjustVO[0]))));
        }
        if (update.size() > 0) {
            ret.addAll(Arrays.asList(dao.update(update.toArray(new AggBudgetAdjustVO[0]))));
        }
        return ret.toArray(new AggBudgetAdjustVO[0]);

    }

    @Override
    public AggBudgetAdjustVO[] callbackSAVE(AggBudgetAdjustVO... vos) throws BusinessException {
        if (ArrayUtils.isEmpty(vos)) {
            return null;
        }
        // 同步单据状态和审批状态(只有提交时候需要手动设置审批状态。其余审批完后审批状态都已更新)
        Arrays.stream(vos).forEach(v -> {
            v.getParent().setAttributeValue("approvestatus", BillStatusEnum.COMMIT.toIntValue());
        });
        List<AggBudgetAdjustVO> update = new ArrayList<>(), insert = new ArrayList<>();
        Arrays.stream(vos).forEach(item -> {
            if (StringUtils.isEmpty(item.getPrimaryKey())) {
                insert.add(item);
            } else {
                update.add(item);
            }
        });
        List<AggBudgetAdjustVO> ret = new ArrayList<>();
        if (insert.size() > 0) {
            ret.addAll(Arrays.asList(dao.insert(insert.toArray(new AggBudgetAdjustVO[0]))));
        }
        if (update.size() > 0) {
            ret.addAll(Arrays.asList(dao.update(update.toArray(new AggBudgetAdjustVO[0]))));
        }
        return ret.toArray(new AggBudgetAdjustVO[0]);

    }

    @Override
    public AggBudgetAdjustVO[] callbackUNSAVE(AggBudgetAdjustVO... vos) throws BusinessException {
        if (ArrayUtils.isEmpty(vos)) {
            return null;
        }
        // 同步单据状态和审批状态(只有提交时候需要手动设置审批状态。其余审批完后审批状态都已更新)
        List<AggBudgetAdjustVO> update = new ArrayList<>(), insert = new ArrayList<>();
        Arrays.stream(vos).forEach(item -> {
            if (StringUtils.isEmpty(item.getPrimaryKey())) {
                insert.add(item);
            } else {
                update.add(item);
            }
        });
        List<AggBudgetAdjustVO> ret = new ArrayList<>();
        if (insert.size() > 0) {
            ret.addAll(Arrays.asList(dao.insert(insert.toArray(new AggBudgetAdjustVO[0]))));
        }
        if (update.size() > 0) {
            ret.addAll(Arrays.asList(dao.update(update.toArray(new AggBudgetAdjustVO[0]))));
        }
        return ret.toArray(new AggBudgetAdjustVO[0]);

    }


    BudgetMakeVOServiceImpl budgetMakeVoServiceImpl = new BudgetMakeVOServiceImpl();

    @Override
    public AggBudgetAdjustVO[] callbackAPPROVE(AggBudgetAdjustVO... vos) throws BusinessException {
        if (ArrayUtils.isEmpty(vos)) {
            return null;
        }

        Map<String, AggBudgetMakeVO> budgetMakeVoMap_beforeAdjust = new HashMap<String, AggBudgetMakeVO>();

        for (AggBudgetAdjustVO item : vos) {
            if (item.getParentVO().getApprovestatus().equals(BillStatusEnum.APPROVED.toIntValue())) {

                String[] pk_budgetmakes = item.getParentVO().getPk_budgetmake().split(",");

                AggBudgetMakeVO[] aggBudgetMakeVos = budgetMakeVoServiceImpl.listAggBudgetMakeVOByPk(pk_budgetmakes);

                for (AggBudgetMakeVO aggBudgetMakeVo : aggBudgetMakeVos) {
                    budgetMakeVoMap_beforeAdjust.put(aggBudgetMakeVo.getPrimaryKey(), aggBudgetMakeVo);
                }

                // 将调整后的数据 同步到预算编制单中
                item = writeMakeBillAdjust(item, "approve");

                // 推送数据到预算执行监控**审批时item表体为空，此处要使用上一步返回item
//                pushBudgetForApproveAndUnApprove(item, budgetMakeVoMap_beforeAdjust, "ADJUST");
                pushBudgetForApproveAndUnApprove(item, "APPROVE");

            }
        }

        // 同步单据状态和审批状态(只有提交时候需要手动设置审批状态。其余审批完后审批状态都已更新)
        List<AggBudgetAdjustVO> update = new ArrayList<>(), insert = new ArrayList<>();
        Arrays.stream(vos).forEach(item -> {
            if (StringUtils.isEmpty(item.getPrimaryKey())) {
                insert.add(item);
            } else {
                update.add(item);
            }
        });
        List<AggBudgetAdjustVO> ret = new ArrayList<>();
        if (insert.size() > 0) {
            ret.addAll(Arrays.asList(dao.insert(insert.toArray(new AggBudgetAdjustVO[0]))));
        }
        if (update.size() > 0) {
            ret.addAll(Arrays.asList(dao.update(update.toArray(new AggBudgetAdjustVO[0]))));
        }
        return ret.toArray(new AggBudgetAdjustVO[0]);

    }

    private AggBudgetAdjustVO writeMakeBillAdjust(AggBudgetAdjustVO adjustVO, String action) throws BusinessException {
        boolean isUnApprove = "unapprove".equals(action);
        if (checkUnapprovedByDimension(new AggBudgetAdjustVO[]{adjustVO}) && isUnApprove) {
            throw new BusinessException("存在未审核完成单据，不允许取消审批/收回！");
        }

        // 1.获取预算编制的pk
        if (action.equals("approve") || isUnApprove) {
            AggBudgetAdjustVO adjustVO_db = findAggBudgetAdjustVOByPk(adjustVO.getPrimaryKey());
            adjustVO_db.setParent(adjustVO.getParentVO());
            adjustVO = adjustVO_db;
        }

        Field[] govPurchFields = GovpurchVO.class.getFields();
        Field[] assetAlFields = AssetAllocationVO.class.getFields();


        Set<String> noProcess = new HashSet<>();
        noProcess.add("DR");
        noProcess.add("TS");
        noProcess.add("PK_GOVPURCH");
        noProcess.add("PK_ASSETALLACTION");
        noProcess.add("PK_BUDGETMAKE");

        noProcess.add("ADJUSTTYPE");

        noProcess.add("OLDNUM");
        noProcess.add("ADJUSTNUM");
//        noProcess.add("NUM");

        noProcess.add("OLDPRICE");
        noProcess.add("ADJUSTPRICE");
//        noProcess.add("PRICE");

        noProcess.add("OLDASSETNUM");
        noProcess.add("ADJUSTASSETNUM");
//        noProcess.add("ASSETNUM");

        noProcess.add("OLDMONEY");
        noProcess.add("ADJUSTMONEY");
//        noProcess.add("MONEY");

        String[] pk_budgetmake = adjustVO.getParentVO().getPk_budgetmake().split(",");
        IBudgetMakeVOService service = NCLocator.getInstance().lookup(IBudgetMakeVOService.class);
        AggBudgetMakeVO[] makeVos = service.listAggBudgetMakeVOByPk(pk_budgetmake);

        ArrayList<BudgetMakeDetailVO> makeDetailInsert = new ArrayList<BudgetMakeDetailVO>();
        ArrayList<GovpurchVO> makeGovpurchInsert = new ArrayList<GovpurchVO>();
        ArrayList<AssetAllocationVO> makeAssetalInsert = new ArrayList<AssetAllocationVO>();
        ArrayList<SpBudgetMakeDetailVO> makeSpBudgetInsert = new ArrayList<SpBudgetMakeDetailVO>();

        Map<String, BudgetMakeDetailVO> detailVOMap = new HashMap<>();
        Map<String, GovpurchVO> govpurchVOMap = new HashMap<>();
        Map<String, AssetAllocationVO> assetAllocationVOMap = new HashMap<>();
		Map<String, SpBudgetMakeDetailVO> spBudgetMakeDetailVOMp = new HashMap<>();

        Set<String> needDelPk = new HashSet<>();

        for (AggBudgetMakeVO makevo : makeVos) {
            BudgetMakeDetailVO[] detailVOS = (BudgetMakeDetailVO[]) makevo.getChildren(BudgetMakeDetailVO.class);
            GovpurchVO[] govpurchVOS = (GovpurchVO[]) makevo.getChildren(GovpurchVO.class);
            AssetAllocationVO[] assetAllocationVOS = (AssetAllocationVO[]) makevo.getChildren(AssetAllocationVO.class);
			SpBudgetMakeDetailVO[] spBudgetMakeDetailVOS = (SpBudgetMakeDetailVO[]) makevo.getChildren(SpBudgetMakeDetailVO.class);



            Optional.ofNullable(detailVOS)
                    .ifPresent(details -> {
                        for (BudgetMakeDetailVO detail : details) {
                            detailVOMap.put(detail.getPk_budgetmakedetail(), detail);
                            needDelPk.add(detail.getPk_budgetmakedetail());
                        }
                    });

            Optional.ofNullable(govpurchVOS)
                    .ifPresent(govpurchs -> {
                        for (GovpurchVO govpurchVO : govpurchs) {
                            govpurchVOMap.put(govpurchVO.getPk_govpurch(), govpurchVO);
                            needDelPk.add(govpurchVO.getPk_govpurch());
                        }
                    });

            Optional.ofNullable(assetAllocationVOS)
                    .ifPresent(assetAlls -> {
                        for (AssetAllocationVO assetAllocationVO : assetAlls) {
                            assetAllocationVOMap.put(assetAllocationVO.getPk_assetallaction(), assetAllocationVO);
                            needDelPk.add(assetAllocationVO.getPk_assetallaction());
                        }
                    });
            // modify by wy
			Optional.ofNullable(spBudgetMakeDetailVOS)
					.ifPresent(assetAlls -> {
						for (SpBudgetMakeDetailVO spBudgetMakeDetailVO : assetAlls) {
							spBudgetMakeDetailVOMp.put(spBudgetMakeDetailVO.getPk_spbudgetmakedetail(), spBudgetMakeDetailVO);
							needDelPk.add(spBudgetMakeDetailVO.getPk_spbudgetmakedetail());
						}
					});

        }


        //调整单数据
        BudgetAdjustDetailVO[] adjustDetailArr =
                (BudgetAdjustDetailVO[]) adjustVO.getChildren(BudgetAdjustDetailVO.class);
        AdjustGovPurchVO[] adjustGovPurchArr = (AdjustGovPurchVO[]) adjustVO.getChildren(AdjustGovPurchVO.class);
        AdjustAssetAllocationVO[] adjustAssetAllocationArr =
                (AdjustAssetAllocationVO[]) adjustVO.getChildren(AdjustAssetAllocationVO.class);
        // modify by wy
		SpBudgetAdjustDetailVO[] spBudgetAdjustDetailArr =
				(SpBudgetAdjustDetailVO[]) adjustVO.getChildren(SpBudgetAdjustDetailVO.class);


        //明细表
        for (BudgetAdjustDetailVO adjustDetail : adjustDetailArr) {
            String srcBillId = adjustDetail.getSrcbillbid();
            BudgetMakeDetailVO makeDetailVO = detailVOMap.get(srcBillId);
            needDelPk.remove(srcBillId);
            UFDouble amount_adjust = adjustDetail.getAmount_adjust();
            if (null != makeDetailVO && adjustDetail.getStatus() != VOStatus.DELETED) {
                // 更新调整数和最终预算数
                updateMakeDetailVo(isUnApprove, amount_adjust, makeDetailVO);
                //更新调整前金额
                adjustDetail.setAmount_before_adjust(isUnApprove ? makeDetailVO.getAmount() :
                        adjustDetail.getAmount_before_adjust());
                adjustDetail.setAmount_after_adjust(isUnApprove ?
                        makeDetailVO.getAmount().sub(adjustDetail.getAmount_adjust()) :
                        adjustDetail.getAmount_after_adjust());
            } else if (null == makeDetailVO && adjustDetail.getStatus() != VOStatus.DELETED) {
                if (!isUnApprove) {
                    BudgetMakeDetailVO newMakeDetail = createNewMakeDetailVo(makeVos, adjustDetail, amount_adjust);
                    makeDetailInsert.add(newMakeDetail);
                }

            }
        }

        // modify by wy
        if(null != spBudgetAdjustDetailArr){
            // 专项指令性预算
            for (SpBudgetAdjustDetailVO SpBudgetAdjustDetailVO : spBudgetAdjustDetailArr) {
                String srcBillId = SpBudgetAdjustDetailVO.getSrcbillbid();
                SpBudgetMakeDetailVO spBudgetMakeDetailVO = spBudgetMakeDetailVOMp.get(srcBillId);
                needDelPk.remove(srcBillId);
                UFDouble amount_adjust = SpBudgetAdjustDetailVO.getAmount_adjust();
                if (null != spBudgetMakeDetailVO && SpBudgetAdjustDetailVO.getStatus() != VOStatus.DELETED) {
                    // 更新调整数和最终预算数
                    updatespBudgetMakeDetailVO(isUnApprove, amount_adjust, spBudgetMakeDetailVO);
                    //更新调整前金额
                    SpBudgetAdjustDetailVO.setAmount_before_adjust(isUnApprove ? spBudgetMakeDetailVO.getAmount() :
                            SpBudgetAdjustDetailVO.getAmount_before_adjust());
                    SpBudgetAdjustDetailVO.setAmount_after_adjust(isUnApprove ?
                            spBudgetMakeDetailVO.getAmount().sub(SpBudgetAdjustDetailVO.getAmount_adjust()) :
                            SpBudgetAdjustDetailVO.getAmount_after_adjust());
                } else if (null == spBudgetMakeDetailVO && SpBudgetAdjustDetailVO.getStatus() != VOStatus.DELETED) {
                    if (!isUnApprove) {
                        SpBudgetMakeDetailVO newMakeDetail = createNewSpBudgetMakeDetailVo(makeVos, SpBudgetAdjustDetailVO, amount_adjust);
                        makeSpBudgetInsert.add(newMakeDetail);
                    }

                }
            }

        }


        if (null != adjustGovPurchArr) {
            //政府采购
            for (AdjustGovPurchVO adjustGovPurch : adjustGovPurchArr) {
                String srcBillId = adjustGovPurch.getSrcbillbid();
                GovpurchVO makeGovpurchVO = govpurchVOMap.get(srcBillId);
                needDelPk.remove(srcBillId);

                if (null != makeGovpurchVO) {
                    updateGovpurchVo(isUnApprove, govPurchFields, noProcess, adjustGovPurch, makeGovpurchVO);
                } else {
                    if (!isUnApprove) {
                        //生成新政府采购数据
                        GovpurchVO newGovpurchVO = new GovpurchVO();
                        processVoFields(govPurchFields, noProcess, adjustGovPurch, newGovpurchVO);
                        newGovpurchVO.setStatus(VOStatus.NEW);
                        newGovpurchVO.setPk_budgetmake(makeVos[makeVos.length - 1].getPrimaryKey());
                        makeGovpurchInsert.add(newGovpurchVO);
                    }

                }

            }
        }


        if (null != adjustAssetAllocationArr) {
            //资产配置
            for (AdjustAssetAllocationVO adjustAssetAll : adjustAssetAllocationArr) {
                String srcbillbid = adjustAssetAll.getSrcbillbid();
                AssetAllocationVO makeAssetAlVO = assetAllocationVOMap.get(srcbillbid);
                needDelPk.remove(srcbillbid);


                if (null != makeAssetAlVO) {
                    makeAssetAlVO.setStatus(isUnApprove ? VOStatus.UPDATED : makeAssetAlVO.getStatus());
                    UFDouble adjustassetnum = getUfDoubleValue(adjustAssetAll.getAdjustassetnum());
                    UFDouble adjustprice = getUfDoubleValue(adjustAssetAll.getAdjustprice());
                    UFDouble adjustmoney = getUfDoubleValue(adjustAssetAll.getAdjustmoney());
                    if (isUnApprove) {
                        makeAssetAlVO.setAssetnum(makeAssetAlVO.getAssetnum().sub(adjustassetnum));
                        makeAssetAlVO.setPrice(makeAssetAlVO.getPrice().sub(adjustprice));
                        makeAssetAlVO.setMoney(makeAssetAlVO.getMoney().sub(adjustmoney));
                    } else {
                        processVoFields(assetAlFields, noProcess, adjustAssetAll, makeAssetAlVO);
                    }
                } else {
                    if (!isUnApprove) {
                        //生成新资产配置数据
                        AssetAllocationVO newAssetAllVO = new AssetAllocationVO();
                        processVoFields(assetAlFields, noProcess, adjustAssetAll, newAssetAllVO);
                        newAssetAllVO.setStatus(VOStatus.NEW);
                        newAssetAllVO.setPk_budgetmake(makeVos[makeVos.length - 1].getPrimaryKey());
                        makeAssetalInsert.add(newAssetAllVO);
                    }
                }
            }
        }


        BudgetMakeDetailVO[] needUpdataDetail =
                (BudgetMakeDetailVO[]) makeVos[makeVos.length - 1].getChildren(BudgetMakeDetailVO.class);
        GovpurchVO[] needUpdataGovPur = (GovpurchVO[]) makeVos[makeVos.length - 1].getChildren(GovpurchVO.class);
        AssetAllocationVO[] needUpdataAssetAl =
                (AssetAllocationVO[]) makeVos[makeVos.length - 1].getChildren(AssetAllocationVO.class);
        // modify by wy
        SpBudgetMakeDetailVO[] needUpdataSpBudgetAl = (SpBudgetMakeDetailVO[] )makeVos[makeVos.length - 1].getChildren(SpBudgetMakeDetailVO.class);


        BudgetMakeDetailVO[] allDetail = mergeArrays(needUpdataDetail, makeDetailInsert, BudgetMakeDetailVO.class);
        Arrays.stream(allDetail).forEach(detailvo -> {
            if (isUnApprove && needDelPk.contains(detailvo.getPk_budgetmakedetail())) {
                detailvo.setStatus(VOStatus.DELETED);
            }
        });
        makeVos[makeVos.length - 1].setChildren(BudgetMakeDetailVO.class, allDetail);

        // modify by wy
        SpBudgetMakeDetailVO[] allspBugetDetail = mergeArrays(needUpdataSpBudgetAl, makeSpBudgetInsert, SpBudgetMakeDetailVO.class);
        Arrays.stream(allspBugetDetail).forEach(spBudgetMakeDetailVO -> {
            if (isUnApprove && needDelPk.contains(spBudgetMakeDetailVO.getPk_spbudgetmakedetail())) {
                spBudgetMakeDetailVO.setStatus(VOStatus.DELETED);
            }
        });
        makeVos[makeVos.length - 1].setChildren(SpBudgetMakeDetailVO.class, allspBugetDetail);
        // end


        GovpurchVO[] allGovPurch = mergeArrays(needUpdataGovPur, makeGovpurchInsert, GovpurchVO.class);
        Arrays.stream(allGovPurch).forEach(govpurchVO -> {
            if (isUnApprove && needDelPk.contains(govpurchVO.getPk_govpurch())) {
                govpurchVO.setStatus(VOStatus.DELETED);
            }
        });
        makeVos[makeVos.length - 1].setChildren(GovpurchVO.class, allGovPurch);

        AssetAllocationVO[] allAssetAl = mergeArrays(needUpdataAssetAl, makeAssetalInsert, AssetAllocationVO.class);
        Arrays.stream(allAssetAl).forEach(allocationVO -> {
            if (isUnApprove && needDelPk.contains(allocationVO.getPk_assetallaction())) {
                allocationVO.setStatus(VOStatus.DELETED);
            }
        });
        makeVos[makeVos.length - 1].setChildren(AssetAllocationVO.class, allAssetAl);

        this.saveAggBudgetMakeVO(makeVos, action, govpurchVOMap.values().toArray(new GovpurchVO[0]),
                assetAllocationVOMap.values().toArray(new AssetAllocationVO[0]));

        return adjustVO;

    }

    /**
     * 按照维度检查是否存在相同维度下存在未审核完成单据
     *
     * @param adjustVO
     * @return 存在 -> true,不存在 -> false
     */
    private boolean checkUnapprovedByDimension(AggBudgetAdjustVO[] adjustVO) throws BusinessException {
        for (AggBudgetAdjustVO aggBudgetAdjustVO : adjustVO) {

            BudgetAdjustVO parentVO = aggBudgetAdjustVO.getParentVO();
            String pk_org = parentVO.getPk_org();
            String nyear = parentVO.getNyear();
            String pk_budgettype = parentVO.getPk_budgettype();
            String pk_budgetdept = parentVO.getPk_budgetdept();
            String pk_budgettask = parentVO.getPk_budgettask();
            String pk_budgetadjust = parentVO.getPk_budgetadjust();
            StringBuilder condition = new StringBuilder();
            condition.append(" pk_org = '").append(pk_org).append("' ");
            condition.append(" and nyear = '").append(nyear).append("' ");
            condition.append(" and pk_budgettype = '").append(pk_budgettype).append("' ");
            condition.append(" and pk_budgetdept = '").append(pk_budgetdept).append("' ");
            condition.append(" and pk_budgettask = '").append(pk_budgettask).append("' ");
            condition.append(" and approvestatus != 1 ");
            condition.append(" and dr != 1 ");
            condition.append(" and pk_budgetadjust != '").append(pk_budgetadjust).append("' ");

            String[] notApproveAdjustMakePK = findNotApproveAdjustMakePK(parentVO.getPk_budgetadjust());
            if (null != notApproveAdjustMakePK && notApproveAdjustMakePK.length > 0) {
                StringBuilder inClause = new StringBuilder();
                for (String pk : notApproveAdjustMakePK) {
                    inClause.append("'").append(pk).append("' ,");
                }

                if (inClause.length() > 0) {
                    // Remove the trailing comma
                    inClause.deleteCharAt(inClause.length() - 1);
                    condition.append(" and pk_budgetmake in ( ").append(inClause).append(" )");
                }
            }

            AggBudgetAdjustVO[] aggBudgetAdjustVOS = listAggBudgetAdjustVOByCondition(condition.toString(), null);
            if (null != aggBudgetAdjustVOS && aggBudgetAdjustVOS.length > 0) {
                return true;
            }
        }

        return false;
    }

    /**
     * 根据编制单号检查是否存在已审批通过的调整单
     *
     * @param adjustVO
     * @return 存在 -> true,不存在 -> false
     */
    public boolean checkApprovedByMakeBillNo(AggBudgetAdjustVO[] adjustVO) throws BusinessException {
        for (AggBudgetAdjustVO aggBudgetAdjustVO : adjustVO) {
            BudgetAdjustVO parentVO = aggBudgetAdjustVO.getParentVO();
            String pk_budgetmake = parentVO.getPk_budgetmake();
            UFDateTime approvedate = parentVO.getApprovedate();
            StringBuilder condition = new StringBuilder();
            condition.append(" approvedate > '").append(approvedate).append("' ");
            if (pk_budgetmake.contains(",")) {
                //多选编制单
                String[] makePkArr = pk_budgetmake.split(",");
                condition.append(" and (");
                for (String s : makePkArr) {
                    condition.append("pk_budgetmake like '%").append(s).append("%' or ");
                }
//                condition.deleteCharAt(condition.length() - 1);
                condition.delete(condition.length() - 3, condition.length());
                condition.append(")");
            } else {
                //单选编制单
                condition.append(" and pk_budgetmake like '%").append(pk_budgetmake).append("%' ");
            }

            AggBudgetAdjustVO[] aggBudgetAdjustVOS = listAggBudgetAdjustVOByCondition(condition.toString(), null);
            if (null != aggBudgetAdjustVOS && aggBudgetAdjustVOS.length > 0) {
                return true;
            }

        }
        return false;
    }

    private void updateGovpurchVo(boolean isUnApprove, Field[] govPurchFields, Set<String> noProcess,
                                  AdjustGovPurchVO adjustGovPurch, GovpurchVO makeGovpurchVO) {
        makeGovpurchVO.setStatus(isUnApprove ? VOStatus.UPDATED : adjustGovPurch.getStatus());
        UFDouble adjustnum = getUfDoubleValue(adjustGovPurch.getAdjustnum());
        UFDouble adjustprice = getUfDoubleValue(adjustGovPurch.getAdjustprice());
        UFDouble adjustmoney = getUfDoubleValue(adjustGovPurch.getAdjustmoney());
        if (isUnApprove) {
            makeGovpurchVO.setNum(makeGovpurchVO.getNum().sub(adjustnum));
            makeGovpurchVO.setPrice(makeGovpurchVO.getPrice().sub(adjustprice));
            makeGovpurchVO.setMoney(makeGovpurchVO.getMoney().sub(adjustmoney));
        } else {
            processVoFields(govPurchFields, noProcess, adjustGovPurch, makeGovpurchVO);
        }
    }




    private void updateMakeDetailVo(boolean isUnApprove, UFDouble amount_adjust,
                                    BudgetMakeDetailVO makeDetailVO) {

        UFDouble makeAmount = getUfDoubleValue(makeDetailVO.getAmount_adjust());
        makeDetailVO.setAmount_adjust(isUnApprove ? makeAmount.sub(amount_adjust) :
                makeAmount.add(amount_adjust));
        makeDetailVO.setAmount(isUnApprove ? makeDetailVO.getAmount().sub(amount_adjust) :
                makeDetailVO.getAmount().add(amount_adjust));

        makeDetailVO.setStatus(VOStatus.UPDATED);

    }
    private void updatespBudgetMakeDetailVO(boolean isUnApprove, UFDouble amount_adjust,
                                            SpBudgetMakeDetailVO spBudgetMakeDetailVO) {

        UFDouble makeAmount = getUfDoubleValue(spBudgetMakeDetailVO.getAmount_adjust());
        spBudgetMakeDetailVO.setAmount_adjust(isUnApprove ? makeAmount.sub(amount_adjust) :
                makeAmount.add(amount_adjust));
        spBudgetMakeDetailVO.setAmount(isUnApprove ? spBudgetMakeDetailVO.getAmount().sub(amount_adjust) :
                spBudgetMakeDetailVO.getAmount().add(amount_adjust));

        spBudgetMakeDetailVO.setStatus(VOStatus.UPDATED);

    }

    private SpBudgetMakeDetailVO createNewSpBudgetMakeDetailVo(AggBudgetMakeVO[] makeVos, SpBudgetAdjustDetailVO spBudgetAdjustDetail,
                                                     UFDouble amount_adjust) {
        SpBudgetMakeDetailVO newspBudgetMakeDetail = new SpBudgetMakeDetailVO();
        newspBudgetMakeDetail.setStatus(VOStatus.NEW);
        newspBudgetMakeDetail.setPk_budgetmake(makeVos[makeVos.length - 1].getPrimaryKey());

        newspBudgetMakeDetail.setBudgetno(spBudgetAdjustDetail.getBudgetno());
        newspBudgetMakeDetail.setPk_project(spBudgetAdjustDetail.getPk_project());
        newspBudgetMakeDetail.setPk_inoutclass(spBudgetAdjustDetail.getPk_inoutclass());
        newspBudgetMakeDetail.setPk_fundsource(spBudgetAdjustDetail.getPk_fundsource());
        newspBudgetMakeDetail.setPk_operation(spBudgetAdjustDetail.getPk_operation());
        newspBudgetMakeDetail.setAmount(spBudgetAdjustDetail.getAmount_after_adjust()); // 调整后的金额
        newspBudgetMakeDetail.setAmount_adjust(amount_adjust);// 调整金额

        return newspBudgetMakeDetail;

    }
    private BudgetMakeDetailVO createNewMakeDetailVo(AggBudgetMakeVO[] makeVos, BudgetAdjustDetailVO adjustDetail,
                                                     UFDouble amount_adjust) {
        BudgetMakeDetailVO newMakeDetail = new BudgetMakeDetailVO();
        newMakeDetail.setStatus(VOStatus.NEW);
        newMakeDetail.setPk_budgetmake(makeVos[makeVos.length - 1].getPrimaryKey());
        newMakeDetail.setPk_fundsource(adjustDetail.getPk_fundsource());
        newMakeDetail.setPk_inoutclass(adjustDetail.getPk_inoutclass());
        newMakeDetail.setPk_project(adjustDetail.getPk_project());
        newMakeDetail.setPk_operation(adjustDetail.getPk_operation());
        newMakeDetail.setAmount(adjustDetail.getAmount_after_adjust());
        newMakeDetail.setAmount_adjust(amount_adjust);
        newMakeDetail.setBudgetno(adjustDetail.getBudgetno());
        newMakeDetail.setDefdim1(adjustDetail.getDefdim1());
        newMakeDetail.setDefdim2(adjustDetail.getDefdim2());
        newMakeDetail.setDefdim3(adjustDetail.getDefdim3());
        newMakeDetail.setDefdim4(adjustDetail.getDefdim4());
        newMakeDetail.setDefdim5(adjustDetail.getDefdim5());
        newMakeDetail.setDefdim6(adjustDetail.getDefdim6());
        newMakeDetail.setDefdim7(adjustDetail.getDefdim7());
        newMakeDetail.setDefdim8(adjustDetail.getDefdim8());
        newMakeDetail.setDefdim9(adjustDetail.getDefdim9());
        newMakeDetail.setDefdim10(adjustDetail.getDefdim10());

        return newMakeDetail;

    }
    private UFDouble getUfDoubleValue(UFDouble value) {
        return value == null ? UFDouble.ZERO_DBL : value;

    }

    private <T> T[] mergeArrays(T[] originalArray, List<T> insertList, Class<T> elementType) {
        if (originalArray == null) {
            originalArray = (T[]) Array.newInstance(elementType, 0); // 创建一个空数组
        }
        T[] allArray = Arrays.copyOf(originalArray, originalArray.length + insertList.size());
        T[] insertArray = insertList.toArray((T[]) Array.newInstance(elementType, insertList.size()));
        System.arraycopy(insertArray, 0, allArray, originalArray.length, insertList.size());
        return allArray;
    }

    private static void processVoFields(Field[] fields, Set<String> noProcess, SuperVO sourceVO, SuperVO targetVO) {
        for (Field field : fields) {
            if (noProcess.contains(field.getName())) {
                continue;
            }
            targetVO.setAttributeValue(field.getName().toLowerCase(),
                    sourceVO.getAttributeValue(field.getName().toLowerCase()));
        }
    }

    public void saveAggBudgetMakeVO(AggBudgetMakeVO[] vos, String action, GovpurchVO[] govpurchVOS,
                                    AssetAllocationVO[] assetAllocationVOS) throws BusinessException {
        for (AggBudgetMakeVO vo : vos) {
            Integer taskCom = -1;
            if (vo.getParentVO().getTaskstate().equals(TaskStateEnum.Complete.toIntValue())) {
                taskCom = TaskStateEnum.Complete.toIntValue();
            }
            // 验证子表不能为空
            ValidateChildLength.validateChildLength(vo);

            setDefaultVal(action, vo);

            // 计算子表vhashcode
            GetIdCode.getIdCode(vo.getAllChildrenVO());

            if (taskCom != -1) {
                vo.getParentVO().setTaskstate(taskCom);
            }

            // 唯一性校验，年度+编制科室+表体行按编制预算维度唯一校验（支出预算+资本预算两种类型一起校验）。
            ValidateBudgetDetail validateBudgetDetail = new ValidateBudgetDetail();
            validateBudgetDetail.validateBudgetDetail(vo, BudgetMakeDetailVO.getDefaultTableName(),
                    BudgetMakeDetailVO.PK_BUDGETMAKEDETAIL);
        }

        if (action.equals("approve") || action.equals("unapprove")) {
            calculateMoneyTotal(vos);
            AggBudgetMakeVO[] aggBudgetMakeVOs = dao.update(vos);
            // 子表数据如果有srcbillid则回写科室上报归口的hassummary和pk_summarybill
            this.rewriteDeptReportByPks(aggBudgetMakeVOs);
            VOUpdate<GovpurchVO> govpurchVOVOUpdate = new VOUpdate<>();
            if (govpurchVOS.length > 0) {
                govpurchVOVOUpdate.update(govpurchVOS);
            }

            VOUpdate<AssetAllocationVO> assetAllocationVOVOUpdate = new VOUpdate<>();
            if (assetAllocationVOS.length > 0) {
                assetAllocationVOVOUpdate.update(assetAllocationVOS);
            }
        }

    }

    private void calculateMoneyTotal(AggBudgetMakeVO[] vos) {
        for (AggBudgetMakeVO vo : vos) {
            BudgetMakeVO parentVO = vo.getParentVO();
            UFDouble govTotal = calculateTotal(vo.getChildren(GovpurchVO.class));
            UFDouble assetTotal = calculateTotal(vo.getChildren(AssetAllocationVO.class));
            parentVO.setGovtotal(govTotal);
            parentVO.setAssettotal(assetTotal);
        }
    }

    private UFDouble calculateTotal(ISuperVO[] children) {
        return Arrays.stream(children)
                .filter(child -> child.getStatus() != VOStatus.DELETED)
                .map(child -> (UFDouble) child.getAttributeValue("money"))
                .reduce(UFDouble.ZERO_DBL, UFDouble::add);
    }


    public void saveAggBudgetMakeVO(AggBudgetMakeVO vo, String action) throws BusinessException {
        String pk = getVOPrimaryKey(vo);
        Integer taskCom = -1;
        if (vo.getParentVO().getTaskstate().equals(TaskStateEnum.Complete.toIntValue())) {
            taskCom = TaskStateEnum.Complete.toIntValue();
        }
        // 验证子表不能为空
        ValidateChildLength.validateChildLength(vo);

        setDefaultVal(action, vo);

        // 计算子表vhashcode
        GetIdCode.getIdCode(vo.getAllChildrenVO());

        if (taskCom != -1) {
            vo.getParentVO().setTaskstate(taskCom);
        }

        // 唯一性校验，年度+编制科室+表体行按编制预算维度唯一校验（支出预算+资本预算两种类型一起校验）。
        ValidateBudgetDetail validateBudgetDetail = new ValidateBudgetDetail();
        validateBudgetDetail.validateBudgetDetail(vo, BudgetMakeDetailVO.getDefaultTableName(),
                BudgetMakeDetailVO.PK_BUDGETMAKEDETAIL);

        if (action.equals("approve")) {
            AggBudgetMakeVO[] aggBudgetMakeVOs = dao.update(vo);
            // 子表数据如果有srcbillid则回写科室上报归口的hassummary和pk_summarybill
            this.rewriteDeptReportByPks(aggBudgetMakeVOs);
        }

    }

    /**
     * 子表数据如果有srcbillid则回写科室上报归口的hassummary和pk_summarybill
     *
     * @throws BusinessException
     */
    private void rewriteDeptReportByPks(AggBudgetMakeVO[] aggvos) throws BusinessException {
        for (AggBudgetMakeVO aggvo : aggvos) {
            CircularlyAccessibleValueObject[] vos = aggvo.getAllChildrenVO();
            String[] pks = {};
            if (Objects.nonNull(aggvo.getParentVO().getSummarybills())) {
                pks = aggvo.getParentVO().getSummarybills().split(",");
            }
            if (pks.length > 0) {
                VOQuery<BudgetMakeVO> budgetmakeQuery = new VOQuery<>(BudgetMakeVO.class);
                BudgetMakeVO[] budgetMakeVOs = budgetmakeQuery.query(pks);
                for (BudgetMakeVO budgetMakeVO : budgetMakeVOs) {
                    budgetMakeVO.setHassummary(UFBoolean.TRUE);
                    budgetMakeVO.setPk_summarybill(aggvo.getParentVO().getPk_budgetmake());
                }
                dao.update(budgetMakeVOs);
            }
        }
    }

    /**
     * 保存前处理一些默认值
     *
     * @param vos
     */
    private void setDefaultVal(String action, AggBudgetMakeVO... vos) throws BusinessException {
        setBillCode(vos);
        setAuditInfo(vos);
        // 其他默认值处理
        // 生成预算号
        GenerateBudgetNo generateBudgetNo = new GenerateBudgetNo();
        generateBudgetNo.generateBudgetNo(vos);
        // 表头年度、编制科室、预算类型赋值给表体字段
        SetChildColumnValue.setChildColumnValue(vos, true);
        // 回写合计金额
        //GettotalMny(action, vos);
    }

    /**
     * 保存前处理编码规则
     *
     * @param vos
     */
    private void setBillCode(AggBudgetMakeVO... vos) throws BusinessException {
        if (ArrayUtils.isNotEmpty(vos)) {
            for (AggBudgetMakeVO vo : vos) {
                String pk = getVOPrimaryKey(vo);
                if (StringUtils.isEmpty(pk)) {
                    BillCodeContext billCodeContext = getBillCodeContext("hrpbmbudgetmake");
                    String pk_group = InvocationInfoProxy.getInstance().getGroupId();
                    if (billCodeContext != null && !billCodeContext.isPrecode()) {
                        if (getMainVO(vo).getAttributeValue("billno") == null) {
                            String code = getBillcodeManage().getBillCode_RequiresNew("hrpbmbudgetmake", pk_group,
                                    pk_group, getMainVO(vo));
                            getMainVO(vo).setAttributeValue("billno", code);
                        }
                    } else {
                        String code = (String) getMainVO(vo).getAttributeValue("billno");
                        getBillcodeManage().commitPreBillCode("hrpbmbudgetmake", pk_group, pk_group, code);
                    }
                }
            }
        }
    }

    /**
     * 保存前设置审计信息
     *
     * @param vos
     */
    private void setAuditInfo(AggBudgetMakeVO... vos) throws BusinessException {
        if (ArrayUtils.isNotEmpty(vos)) {
            UFDateTime now = new UFDateTime();
            for (AggBudgetMakeVO vo : vos) {
                String pk = getVOPrimaryKey(vo);
                if (StringUtils.isEmpty(pk)) {
                    // 设置创建人创建时间
                    getMainVO(vo).setAttributeValue("creator", InvocationInfoProxy.getInstance().getUserId());
                    getMainVO(vo).setAttributeValue("creationtime", now);
                    getMainVO(vo).setAttributeValue("billmaketime", now);
                } else {
                    // 设置修改人修改时间
                    getMainVO(vo).setAttributeValue("modifier", InvocationInfoProxy.getInstance().getUserId());
                    getMainVO(vo).setAttributeValue("modifiedtime", now);
                    getMainVO(vo).setAttributeValue("lastmaketime", now);
                }
            }
        }
    }

    private void GettotalMny(String action, AggBudgetMakeVO... vos) {
        for (AggBudgetMakeVO aggVo : vos) {
            if (!action.equals("approve")) {
                aggVo.getParentVO().setTotalamount(UFDouble.ZERO_DBL);
            }
            BudgetMakeDetailVO[] detailVOs = (BudgetMakeDetailVO[]) aggVo.getChildren(BudgetMakeDetailVO.class);
            UFDouble totalMny = UFDouble.ZERO_DBL;
            for (BudgetMakeDetailVO detailVO : detailVOs) {
                if (aggVo.getParentVO().getTaskstage().equals(TaskStageEnum.FirstUp.toIntValue())) {
                    if (Objects.nonNull(detailVO.getAmount_firstup())) {
                        totalMny = totalMny.add(new UFDouble(detailVO.getAmount_firstup()));
                    }
                }
                if (aggVo.getParentVO().getTaskstage().equals(TaskStageEnum.SecondUp.toIntValue())) {
                    if (Objects.nonNull(detailVO.getAmount_secondup())) {
                        totalMny = totalMny.add(new UFDouble(detailVO.getAmount_secondup()));
                    }
                }
            }
            if (!action.equals("approve")) {
                aggVo.getParentVO().setTotalamount(totalMny);
            }

        }
    }

    /**
     * 推送数据到预算执行监控
     *
     */
//	public void pushDataToControl(AggBudgetAdjustVO[] adjustVos, String action) throws BusinessException {
//
//		for (int i = 0; i < adjustVos.length; i++) {
//
//			AggBudgetAdjustVO adjustVo = (AggBudgetAdjustVO) adjustVos[i].clone();
//			BudgetAdjustVO parentVo = adjustVo.getParentVO();
//
//			if (!parentVo.getApprovestatus().equals(ApproveStatus.APPROVED)) {
//				continue;
//			}
//
//			if (adjustVo.getAllChildrenVO() == null || adjustVo.getAllChildrenVO().length == 0) {
//
//				adjustVo = this.findAggBudgetAdjustVOByPk(adjustVo.getPrimaryKey());
//
//			}
//
//			// 记录发生调整的预算编制单行
//			Map<String, BudgetAdjustDetailVO> adjustDetailMap = new HashMap<String, BudgetAdjustDetailVO>();
//			BudgetAdjustDetailVO[] adjustDetails = (BudgetAdjustDetailVO[]) adjustVo
//					.getChildren(BudgetAdjustDetailVO.class);
////			List<BudgetAdjustDetailVO> adjustDetailList = new ArrayList<BudgetAdjustDetailVO>();
//			for (BudgetAdjustDetailVO adjustDetail : adjustDetails) {
//
//				if (adjustDetail.getAmount_adjust() != null
//						&& adjustDetail.getAmount_adjust().compareTo(UFDouble.ZERO_DBL) != 0) {
////					adjustDetailList.add(adjustDetail);
//
//					adjustDetailMap.put(adjustDetail.getBudgetno(), adjustDetail);
//
//				}
//
//			}
//
//			if (adjustDetailMap.size() > 0) {
//
//				/*
//				 * 通过预算编制单据进行业务控制数据的推送 查询调整单中发生调整的行对应的预算编制行（包括调整预算的以及新增维度的）
//				 */
//				AggBudgetMakeVO budgetMakeVo = new BudgetMakeVOServiceImpl()
//						.findAggBudgetMakeVOByPk(adjustVo.getParentVO().getPk_budgetmake());
//				List<BudgetMakeDetailVO> adjustMakeDetailList = new ArrayList<BudgetMakeDetailVO>();
//
//				BudgetMakeDetailVO[] makeDetails = (BudgetMakeDetailVO[]) budgetMakeVo
//						.getChildren(BudgetMakeDetailVO.class);
//				makeDetails = makeDetails == null ? new BudgetMakeDetailVO[0] : makeDetails;
//				if (budgetMakeVo.getAllChildrenVO() != null) {
//
//					BudgetAdjustDetailVO tempAdjustDetail = null;
//
//					for (BudgetMakeDetailVO makeDetail : makeDetails) {
//
//						tempAdjustDetail = adjustDetailMap.get(makeDetail.getBudgetno());
//
//						if (tempAdjustDetail != null) {
//
//							makeDetail.setAmount(tempAdjustDetail.getAmount_adjust());
//
//							adjustMakeDetailList.add(makeDetail);
//
//						}
//
//					}
//
//				}
//
//				// 重新设置子表
//				budgetMakeVo.setChildren(BudgetMakeDetailVO.class,
//						adjustMakeDetailList.toArray(new BudgetMakeDetailVO[0]));
//
//				new BmBudgetControlServiceImpl().pushDataToControl(parentVo.getPk_group(), parentVo.getPk_org(),
//				"BM20",
//						null, null, action, budgetMakeVo, null);
//
//			}
//
//		}
//
//	}

//    /**
//     * 推送数据到业务控制平台
//     *
//     * @param adjustVo
//     * @param budgetMakeVoMap_beforeAdjust
//     * @param action
//     * @throws BusinessException
//     */
//    public void pushBudgetForApproveAndUnApprove(AggBudgetAdjustVO adjustVo,
//                                                 Map<String, AggBudgetMakeVO> budgetMakeVoMap_beforeAdjust,
//                                                 String action) throws BusinessException {
//
////        for (int i = 0; i < adjustVos.length; i++) {
//
////            AggBudgetAdjustVO adjustVo = (AggBudgetAdjustVO) adjustVos[i].clone();
//        BudgetAdjustVO parentVo = adjustVo.getParentVO();
//
//        BmBudgetControlServiceImpl bmBudgetControlServiceImplnew = new BmBudgetControlServiceImpl();
//
////            adjustVo = this.findAggBudgetAdjustVOByPk(adjustVo.getPrimaryKey());
//
//        String[] pk_budgetmakes = parentVo.getPk_budgetmake().split(",");
//
//
//        AggBudgetMakeVO budgetMakeVo_beforeAdjust = null;
//        AggBudgetMakeVO budgetMakeVo_afterAdjust = null;
//        for (String pk_budgetmake : pk_budgetmakes) {
//
//            //获取变更前的预算编制单
//            budgetMakeVo_beforeAdjust = budgetMakeVoMap_beforeAdjust.get(pk_budgetmake);
//
//            //查询变更后的预算编制单
//            budgetMakeVo_afterAdjust = budgetMakeVoServiceImpl.findAggBudgetMakeVOByPk(pk_budgetmake);
//
//            //推送数据到业务控制平台
//            bmBudgetControlServiceImplnew.pushDataToControl(parentVo.getPk_group(), parentVo.getPk_org(), "BM20",
//                    null, null, action, budgetMakeVo_afterAdjust, budgetMakeVo_beforeAdjust, true);
//
//        }
//
////        }
//
//    }

    /**
     * 推送数据到业务控制平台
     *
     * @param adjustVo
     * @param action
     * @throws BusinessException
     */
    public void pushBudgetForApproveAndUnApprove(AggBudgetAdjustVO adjustVo, String action) throws BusinessException {

        //！！这里必须重新查询！！
        adjustVo = findAggBudgetAdjustVOByPk(adjustVo.getPrimaryKey());

        //ADD BY WW 2025-02-25 过滤掉没有发生调整的行
        BudgetAdjustDetailVO[] adjustDetails = (BudgetAdjustDetailVO[]) adjustVo.getChildren(BudgetAdjustDetailVO.class);
        adjustDetails = this.filterAdjustDetails(adjustDetails);
        adjustVo.setChildrenVO(adjustDetails);

        BmBudgetControlServiceImpl bmBudgetControlServiceImplnew = new BmBudgetControlServiceImpl();

        //推送数据到业务控制平台
        bmBudgetControlServiceImplnew.pushDataToControl(adjustVo.getParentVO().getPk_group(),
                adjustVo.getParentVO().getPk_org(), "BM30",
                null, null, action, adjustVo, null, true);

    }

    /**
     * 保存时 推送预算（校验余额、冻结）
     *
     * @param adjustVos
     * @param oriAdjustVo
     * @param isNeedCheck 是否进行校验
     * @throws BusinessException
     */
    public void pushBudgetForSave(AggBudgetAdjustVO adjustVos, AggBudgetAdjustVO oriAdjustVo, boolean isNeedCheck) throws BusinessException {

//		for (int i = 0; i < adjustVos.length; i++) {

        AggBudgetAdjustVO adjustVo = (AggBudgetAdjustVO) adjustVos.clone();
        BudgetAdjustVO parentVo = adjustVo.getParentVO();

        if (adjustVo.getAllChildrenVO() == null || adjustVo.getAllChildrenVO().length == 0) {

            adjustVo = this.findAggBudgetAdjustVOByPk(adjustVo.getPrimaryKey());

        }

        // 过滤掉没有发生调整的行
        BudgetAdjustDetailVO[] adjustDetails =
                (BudgetAdjustDetailVO[]) adjustVo.getChildren(BudgetAdjustDetailVO.class);
        adjustDetails = this.filterAdjustDetails(adjustDetails);

        if (adjustDetails.length > 0) {

            adjustVo.setChildrenVO(adjustDetails);

            if (oriAdjustVo != null) {

                BudgetAdjustDetailVO[] oriAdjustDetails =
                        (BudgetAdjustDetailVO[]) oriAdjustVo.getChildren(BudgetAdjustDetailVO.class);
                oriAdjustDetails = this.filterAdjustDetails(oriAdjustDetails);

                if (oriAdjustDetails.length > 0) {

                    oriAdjustVo.setChildrenVO(oriAdjustDetails);

                }

            }

            new BmBudgetControlServiceImpl().pushDataToControl(parentVo.getPk_group(), parentVo.getPk_org(), "BM30",
                    null, null, "SAVE", adjustVo, oriAdjustVo, isNeedCheck);

        }

//		}

    }

    /**
     * 过滤没有发生调整的行
     *
     * @param adjustDetails
     * @return
     */
    private BudgetAdjustDetailVO[] filterAdjustDetails(BudgetAdjustDetailVO[] adjustDetails) {

        List<BudgetAdjustDetailVO> adjustDetailList = new ArrayList<BudgetAdjustDetailVO>();
        for (BudgetAdjustDetailVO adjustDetail : adjustDetails) {

            if (adjustDetail.getAmount_adjust() != null
                    && adjustDetail.getAmount_adjust().compareTo(UFDouble.ZERO_DBL) != 0) {
                adjustDetailList.add(adjustDetail);
            }

        }

        return adjustDetailList.toArray(new BudgetAdjustDetailVO[0]);

    }


    @Override
    public AggBudgetAdjustVO[] callbackUNAPPROVE(AggBudgetAdjustVO... vos) throws BusinessException {
        if (ArrayUtils.isEmpty(vos)) {
            return null;
        }

        //记录取消审批前的编制单
        Map<String, AggBudgetMakeVO> budgetMakeVoMap_before = new HashMap<String, AggBudgetMakeVO>();

        //同步单据状态和审批状态(只有提交时候需要手动设置审批状态。其余审批完后审批状态都已更新)
        List<AggBudgetAdjustVO> update = new ArrayList<>(), insert = new ArrayList<>();
        Arrays.stream(vos).forEach(item -> {
            try {
                BudgetAdjustVO sourceAdjust = findBudgetAdjustVOByPk(item.getPrimaryKey());
                int approvestatus_before = sourceAdjust.getApprovestatus();

                if (approvestatus_before == BillStatusEnum.APPROVED.toIntValue()
                        && item.getParentVO().getApprovestatus() != BillStatusEnum.APPROVED.toIntValue()) {
                    //由审批通过变成非审批通过时，回写编制单 并推送预算

                    //查询取消审批回写之前的预算编制单
                    String[] pk_budgetmakes = item.getParentVO().getPk_budgetmake().split(",");
                    AggBudgetMakeVO[] aggBudgetMakeVos = new AggBudgetMakeVO[0];

                    aggBudgetMakeVos = budgetMakeVoServiceImpl.listAggBudgetMakeVOByPk(pk_budgetmakes);
                    for (AggBudgetMakeVO aggBudgetMakeVo : aggBudgetMakeVos) {
                        budgetMakeVoMap_before.put(aggBudgetMakeVo.getPrimaryKey(), aggBudgetMakeVo);
                    }

                    // 将调整后的数据 同步到预算编制单中
                    item = writeMakeBillAdjust(item, "unapprove");

                    // 推送数据到预算执行监控
//                    pushBudgetForApproveAndUnApprove(item, budgetMakeVoMap_before, "UNADJUST");
                    pushBudgetForApproveAndUnApprove(item, "UNAPPROVE");


                    if (StringUtils.isEmpty(item.getPrimaryKey())) {
                        insert.add(item);
                    } else {
                        update.add(item);
                    }

                }
            } catch (BusinessException e) {
                throw new RuntimeException(e);
            }


        });

        List<AggBudgetAdjustVO> ret = new ArrayList<>();
        if (insert.size() > 0) {
            ret.addAll(Arrays.asList(dao.insert(insert.toArray(new AggBudgetAdjustVO[0]))));
        }
        if (update.size() > 0) {
            ret.addAll(Arrays.asList(dao.update(update.toArray(new AggBudgetAdjustVO[0]))));
        }
        return ret.toArray(new AggBudgetAdjustVO[0]);

    }

    @Override
    public String[] findNotApproveAdjustMakePK(String pk_budgetadjust) throws BusinessException {
        List<String> pkList = new ArrayList<>();
        String sql = "select pk_budgetmake from hrpbm_budgetadjust where APPROVESTATUS not in ('1','0') ";
        if (StringUtils.isNotEmpty(pk_budgetadjust)) {
            sql += "and pk_budgetadjust != ' + pk_budgetadjust + '";
        }
        List<String> budgetmakepks = (List<String>) daoSql.executeQuery(sql, new ColumnListProcessor());
        for (String pk : budgetmakepks) {
            if (pk.contains(",")) {
                String[] pkArr = pk.split(",");
                for (String pkmake : pkArr) {
                    pkList.add(pkmake);
                }
            }
            pkList.add(pk);

        }
        return pkList.toArray(new String[0]);
    }

}